package com.hsmpay.mobile.util.icc;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**
 * 3DES
 * 设Ek()和Dk()代表DES算法的加密和解密过程，K代表DES算法使用的密钥，P代表明文，C代表密表，
 * 3DES加密过程为： C=Ek3(Dk2(Ek1(P)))
 * 　*　3DES解密过程为： P=Dk1((EK2(Dk3(C)))
 */
public final class DESUtil {
    /**
     * 3DES 加密
     *
     * @param key
     * @param data
     * @return
     */
    public static byte[] tripleDESEncrypt(DESKey key, byte[] data) {
        byte[] result = null;
        try {
            SecretKeySpec keySpecA = new SecretKeySpec(key.getPartA(), "DES");
            SecretKeySpec keySpecB = new SecretKeySpec(key.getPartB(), "DES");
            SecretKeySpec keySpecC = new SecretKeySpec(key.getPartC(), "DES");
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, keySpecA);
            result = cipher.doFinal(data);
            cipher.init(Cipher.DECRYPT_MODE, keySpecB);
            result = cipher.doFinal(result);
            cipher.init(Cipher.ENCRYPT_MODE, keySpecC);
            result = cipher.doFinal(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * DES 加密
     *
     * @param key
     * @param offset
     * @param data
     * @return
     */
    public static byte[] DESEncrypt(byte[] key, int offset, byte[] data) {
        byte[] result = null;
        try {
            byte[] theKey = new byte[8];
            System.arraycopy(key, offset, theKey, 0, 8);
            SecretKeySpec keySpecC = new SecretKeySpec(theKey, "DES");
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, keySpecC);
            result = cipher.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * des密钥解密
     *
     * @param key
     * @param offset
     * @param data
     * @return
     */
    public static byte[] DESDecrypt(byte[] key, int offset, byte[] data) {
        byte[] result = null;
        try {
            byte[] theKey = new byte[8];
            System.arraycopy(key, offset, theKey, 0, 8);
            SecretKeySpec keySpecC = new SecretKeySpec(theKey, "DES");
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, keySpecC);
            result = cipher.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 3DES 解密密
     *
     * @param key
     * @param data
     * @return
     */
    public static byte[] tripleDESDecrypt(DESKey key, byte[] data) {
        byte[] result = null;
        try {
            SecretKeySpec keySpecA = new SecretKeySpec(key.getPartA(), "DES");
            SecretKeySpec keySpecB = new SecretKeySpec(key.getPartB(), "DES");
            SecretKeySpec keySpecC = new SecretKeySpec(key.getPartC(), "DES");
            Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, keySpecA);
            result = cipher.doFinal(data);
            cipher.init(Cipher.ENCRYPT_MODE, keySpecB);
            result = cipher.doFinal(result);
            cipher.init(Cipher.DECRYPT_MODE, keySpecC);
            result = cipher.doFinal(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 3des CBC 模式 加密
     *
     * @param key
     * @param data
     * @return
     */
    public static byte[] tripleDESEncryptCBC(DESKey key, byte[] data) {
        byte[] IV = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

        byte[] plain = new byte[8];
        int blockNum = (data.length + 7) / 8;
        byte[] result = new byte[blockNum * 8];
        int byteIndex = 0;

        for (int i = 0; i < blockNum; i++) {
            for (int j = 0; j < 8; j++) {
                if (byteIndex < data.length) plain[j] = data[byteIndex++];
                else plain[j] = 0x00;
                plain[j] ^= IV[j];

            }
            IV = tripleDESEncrypt(key, plain);
            for (int j = 0; j < 8; j++) {
                result[i * 8 + j] = IV[j];
            }

        }
        return result;


    }

    /**
     * 3des CBC 模式 解密
     *
     * @param key
     * @param data
     * @return
     */
    public static byte[] tripleDESDecryptCBC(DESKey key, byte[] data) {
        byte[] IV = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        byte[] c = new byte[8];
        byte[] plain;
        int blockNum = (data.length) / 8;
        byte[] result = new byte[data.length];

        int byteIndex = 0;

        for (int i = 0; i < blockNum; i++) {
            for (int j = 0; j < 8; j++) {
                if (byteIndex < data.length) c[j] = data[byteIndex++];
                else c[j] = 0x00;
            }
            plain = tripleDESDecrypt(key, c);

            for (int j = 0; j < 8; j++) {
                result[i * 8 + j] = (byte) (plain[j] ^ IV[j]);
                IV[j] = c[j];
            }
        }
        return result;


    }
}
